package com.buddy.learn.javasource._lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * @author Buddy
 * @date 2021/5/15
 */
public class _MyReentrantLock implements Lock {

    private static class Sync extends AbstractQueuedSynchronizer {

        // 尝试获取锁
        @Override
        protected boolean tryAcquire(int arg) {
            int stat = super.getState();
            // 如果 stat = 0，表示无锁，反之，有锁
            // 第一次加锁
            if (super.compareAndSetState(0, 1)) {
                super.setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            // 如果当前线程与占用锁的线程一致,表明线程重入
            if (Thread.currentThread() == super.getExclusiveOwnerThread()) {
                super.compareAndSetState(stat, stat + 1);
                return true;
            }
            // 返回 false，该线程将会加入到同步队列中进行等待。
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            // 这个方法只有拿到线程的锁会进入，也就是只有一个线程会进入此方法
            int stat = super.getState();
            // 进行 -1 操作
            super.setState(stat - 1);
            // 如果为0，表明已经完全释放锁了，把当前占用线程设置为空
            if (super.getState() == 0) {
                super.setExclusiveOwnerThread(null);
            }
            return true;
        }

        // 判断是否被占用
        @Override
        protected boolean isHeldExclusively() {
            return super.getState() > 0;
        }
    }

    private Sync sync = new Sync();

    @Override
    public void lock() {
        sync.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return tryLock();
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return null;
    }
}
